//
// Created by pengmutian on 2025/9/30.
//

#include <jni.h>
#include <android/log.h>
#include <cmath>
#include <cstring>
#include <vector>

#define LOG_TAG "ImageProcessing"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

// 高斯核生成函数
std::vector<float> generateGaussianKernel(int radius) {
    int size = 2 * radius + 1;
    std::vector<float> kernel(size);
    float sigma = radius / 3.0f;
    float sum = 0.0f;

    for (int i = 0; i < size; i++) {
        int x = i - radius;
        kernel[i] = expf(-(x * x) / (2 * sigma * sigma));
        sum += kernel[i];
    }

    // 归一化
    for (int i = 0; i < size; i++) {
        kernel[i] /= sum;
    }

    return kernel;
}

// 水平方向高斯模糊
void gaussianBlurHorizontal(const unsigned char* input, unsigned char* output,
                            int width, int height, const std::vector<float>& kernel, int radius) {
    int kernelSize = kernel.size();

    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            float sum = 0.0f;
            for (int k = 0; k < kernelSize; k++) {
                int nx = x + k - radius;
                // 边界处理：镜像复制
                if (nx < 0) nx = -nx;
                if (nx >= width) nx = 2 * width - nx - 2;

                sum += input[y * width + nx] * kernel[k];
            }
            output[y * width + x] = static_cast<unsigned char>(sum);
        }
    }
}

// 垂直方向高斯模糊
void gaussianBlurVertical(const unsigned char* input, unsigned char* output,
                          int width, int height, const std::vector<float>& kernel, int radius) {
    int kernelSize = kernel.size();

    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            float sum = 0.0f;
            for (int k = 0; k < kernelSize; k++) {
                int ny = y + k - radius;
                // 边界处理：镜像复制
                if (ny < 0) ny = -ny;
                if (ny >= height) ny = 2 * height - ny - 2;

                sum += input[ny * width + x] * kernel[k];
            }
            output[y * width + x] = static_cast<unsigned char>(sum);
        }
    }
}

extern "C" JNIEXPORT jbyteArray JNICALL
Java_com_pmt_jnipractice_NativeImageUtils_applyGaussianBlur(
        JNIEnv *env,
        jobject clazz,
        jbyteArray input,
        jint width,
        jint height,
        jint radius) {

    if (input == nullptr) {
        LOGE("Input array is null");
        return nullptr;
    }

    jsize inputLength = env->GetArrayLength(input);
    if (inputLength != width * height) {
        LOGE("Input array length does not match width * height");
        return nullptr;
    }

    // 获取输入数据
    jbyte *inputData = env->GetByteArrayElements(input, nullptr);
    if (inputData == nullptr) {
        LOGE("Failed to get input array elements");
        return nullptr;
    }

    // 创建输出数组
    jbyteArray result = env->NewByteArray(inputLength);
    if (result == nullptr) {
        env->ReleaseByteArrayElements(input, inputData, JNI_ABORT);
        LOGE("Failed to create result array");
        return nullptr;
    }

    if (radius <= 0) {
        // 半径为0，直接复制原图
        env->SetByteArrayRegion(result, 0, inputLength, inputData);
        env->ReleaseByteArrayElements(input, inputData, JNI_ABORT);
        return result;
    }

    // 转换为unsigned char进行处理
    auto *src = reinterpret_cast<unsigned char *>(inputData);

    // 分配临时缓冲区
    std::vector<unsigned char> tempBuffer(width * height);
    std::vector<unsigned char> outputBuffer(width * height);

    try {
        // 生成高斯核
        std::vector<float> kernel = generateGaussianKernel(radius);

        // 水平模糊
        gaussianBlurHorizontal(src, tempBuffer.data(), width, height, kernel, radius);

        // 垂直模糊
        gaussianBlurVertical(tempBuffer.data(), outputBuffer.data(), width, height, kernel, radius);

        // 将结果复制回Java数组
        jbyte* resultData = reinterpret_cast<jbyte *>(outputBuffer.data());
        env->SetByteArrayRegion(result, 0, inputLength, resultData);

    } catch (const std::exception &e) {
        LOGE("Exception in gaussian blur: %s", e.what());
        env->ReleaseByteArrayElements(input, inputData, JNI_ABORT);
        return nullptr;
    }

    // 释放资源
    env->ReleaseByteArrayElements(input, inputData, JNI_ABORT);

    return result;
}


